home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-07-18 | 24.5 KB | 940 lines |
- // @(#)ServletGateConnection.java 1.20 97/05/22
- //
- // ServletGateConnection - a program that runs Servlets
- //
- // Copyright (c) 1996 Sun Microsystems, Inc. All Rights reserved
- // Permission to use, copy, modify, and distribute this software
- // and its documentation for NON-COMMERCIAL purposes and without
- // fee is hereby granted provided that this copyright notice
- // appears in all copies. Please refer to the file copyright.html
- // for further important copyright and licensing information.
- //
- // SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- // THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- // TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- // PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- // ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- // DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
-
- package sun.servlet.apache;
-
- import java.io.*;
- import java.util.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.util.StringTokenizer;
-
- /** A program that runs Servlets.
- ** <P>
- ** This is a web program in java, but instead of actually serving
- ** content it instead turns the web requests into Jeeves-compatible
- ** Servlet requests, and then runs the Servlets.
- */
-
- public abstract class ServletGateConnection
- implements HttpServletRequest, HttpServletResponse {
-
- protected ServletGate serve;
-
- protected ServletInputStream in;
- protected ServletOutputStream out;
-
- /** Constructor.
- */
- public ServletGateConnection(ServletGate serve, InputStream in,
- OutputStream out ) {
- // Save arguments.
- this.serve = serve;
-
- // Make the streams.
- this.in = makeServletInputStream( in );
- this.out = makeServletOutputStream( out );
-
- }
-
- protected ServletInputStream makeServletInputStream( InputStream in ) {
- return new AServletInputStream( in );
- }
-
- protected ServletOutputStream makeServletOutputStream( OutputStream out ) {
- return new AServletOutputStream( out, this );
- }
-
- private final String PREFIX = "/servlet/";
-
- protected void handle() {
- String requestPath = getRequestPath();
- String servletName = null;
-
- if (requestPath != null && requestPath.startsWith(PREFIX)
- && requestPath.length() > PREFIX.length()) {
-
- servletName = requestPath.substring(PREFIX.length());
- // Strip off path info
- if (servletName.indexOf("/") != -1) {
- servletName = servletName.substring(0,servletName.indexOf("/"));
- }
-
- Servlet servlet = findServlet( servletName );
- if ( servlet != null )
- runServlet( servlet );
- }
- }
-
- protected Servlet findServlet( String servletName ) {
- // See if we have already instantiated this one.
- Servlet servlet = (Servlet) serve.servlets.get( servletName );
- if ( servlet != null )
- return servlet;
-
- // Make a new one.
- try {
- String cname =
- serve.servletProperties.getProperty("servlet."+
- servletName+".code");
- String initArgs =
- serve.servletProperties.getProperty("servlet."+
- servletName+".initArgs");
- if (cname == null) cname = servletName;
- servlet = (Servlet) Class.forName(cname).newInstance();
- servlet.init(new ServletGateConfig((ServletContext)serve,
- servletName,initArgs));
- serve.servlets.put( servletName, servlet );
- return servlet;
- }
- catch ( ClassNotFoundException e ) {
- problem("Class not found: " + servletName,
- SC_NOT_FOUND );
- }
- catch ( ClassCastException e ) {
- problem("Class cast problem: " + e.getMessage(),
- SC_INTERNAL_SERVER_ERROR );
- }
- catch ( InstantiationException e ) {
- problem(
- "Instantiation problem: " + e.getMessage(),
- SC_INTERNAL_SERVER_ERROR );
- }
- catch ( IllegalAccessException e ) {
- problem(
- "Illegal class access: " + e.getMessage(),
- SC_FORBIDDEN );
- }
- catch ( Exception e ) {
- problem( e.toString(), SC_INTERNAL_SERVER_ERROR, e );
- }
-
- // Failure.
- return null;
- }
-
- protected void runServlet( Servlet servlet ) {
- // Set default response fields.
- setStatus( SC_OK );
- setHeader( "Server", serve.serverName() );
- setDateHeader( "Date", System.currentTimeMillis() );
- try {
- servlet.service( this, this );
- }
- catch (Throwable t) {
- problem( t.toString(), SC_INTERNAL_SERVER_ERROR, t );
- }
- }
-
- protected void problem( String logMessage, int resCode ) {
- serve.log( logMessage );
- try {
- sendError( resCode );
- }
- catch (IOException ignore) { }
- }
-
- protected void problem( String logMessage, int resCode, Throwable t )
- {
- serve.log( logMessage );
- serve.log( t );
- try {
- sendError( resCode, t.toString() );
- }
- catch (IOException ignore) { }
- }
-
- // Methods from HttpServletRequest.
-
- /**
- * Returns a particular variable for this request.
- */
- public abstract String getVar( String name );
- public abstract Enumeration getVars();
-
- /**
- * Returns the method with which the request was made. This can be "GET",
- * "HEAD", "POST", or an extension method.
- * Same as the CGI variable REQUEST_METHOD.
- */
- public String getMethod() {
- return getVar( "REQUEST_METHOD" );
- }
-
- /**
- * Returns the size of the request entity data, or -1 if not known.
- * Same as the CGI variable CONTENT_LENGTH.
- */
- public int getContentLength() {
- try {
- return Integer.parseInt( getVar( "CONTENT_LENGTH" ) );
- }
- catch ( NumberFormatException e ) {
- return -1;
- }
- }
-
- /**
- * Returns the MIME type of the request entity data, or null if
- * not known.
- * Same as the CGI variable CONTENT_TYPE.
- */
- public String getContentType() {
- return getVar( "CONTENT_TYPE" );
- }
-
- /**
- * Returns the full request URI.
- */
- public String getRequestURI() {
- String queryPart = "";
- String queryString = getQueryString();
- if ( queryString != null && queryString.length() > 0 )
- queryPart = "?" + queryString;
- return getRequestPath() + queryPart;
- }
-
- /**
- * Returns the part of the request URI that corresponds to the
- * servlet path plus the optional extra path information, if any
- */
- private String getRequestPath() {
- String pi = getPathInfo();
- if ( pi == null )
- return getServletPath();
- else
- return getServletPath() + getPathInfo();
- }
-
-
- /**
- * Returns the translated path for the specified virtual path.
- */
- public String getRealPath(String path) {
- return null;
- }
-
-
- /**
- * Returns the part of the request URI that referred to the servlet being
- * invoked.
- * Analogous to the CGI variable SCRIPT_NAME.
- */
- public String getServletPath() {
- return getVar( "SCRIPT_NAME" );
- }
-
- /** Returns optional extra path information following the servlet path, but
- * immediately preceding the query string. Returns null if not specified.
- * Same as the CGI variable PATH_INFO.
- */
- public String getPathInfo() {
- return getVar( "PATH_INFO" );
- }
-
- /**
- * Returns extra path information translated to a real path. Returns
- * null if no extra path information was specified.
- * Same as the CGI variable PATH_TRANSLATED.
- */
- public String getPathTranslated() {
- return getVar( "PATH_TRANSLATED" );
- }
-
- /**
- * Returns the query string part of the servlet URI, or null if not known.
- * Same as the CGI variable QUERY_STRING.
- */
- public String getQueryString() {
- return getVar( "QUERY_STRING" );
- }
-
- private Dictionary params = null;
-
- /**
- * Returns the value of the specified query string parameter, or null
- * if not found.
- * @param name the parameter name
- */
- public String getParameter( String name ) {
-
- if (params == null)
- params = getParametersFromRequest();
-
- String vals[] = (String []) params.get(name);
-
- if (vals == null)
- return null;
-
- String hackVal = vals[0];
- for (int i = 1; i < vals.length; i++)
- hackVal = hackVal + "," + vals[i];
-
- return hackVal;
- }
-
- /**
- * Returns an array of values for the specified query parameter.
- */
- public String [] getParameterValues(String name) {
-
- if (params == null)
- params = getParametersFromRequest();
-
- return (String []) params.get(name);
- }
-
- /**
- * Returns an enumeration of parameter names.
- */
- public Enumeration getParameterNames() {
-
- if (params == null)
- params = getParametersFromRequest();
-
- return params.keys();
-
- }
-
- /**
- * Returns the protocol and version of the request as a string of
- * the form <protocol>/<major version>.<minor version>.
- * Same as the CGI variable SERVER_PROTOCOL.
- */
- public String getProtocol() {
- return getVar( "SERVER_PROTOCOL" );
- }
-
- /**
- * Returns the scheme of the request -- always "http" for now.
- */
- public String getScheme() {
- return "http"; // XXX might be "https" too!
- }
-
- /**
- * Returns the host name of the server as used in the <host> part of
- * the request URI.
- * Same as the CGI variable SERVER_NAME.
- */
- public String getServerName() {
- return getVar( "SERVER_NAME" );
- }
-
- /**
- * Returns the port number on which this request was received as used in
- * the <port> part of the request URI.
- * Same as the CGI variable SERVER_PORT.
- */
- public int getServerPort() {
- try {
- return Integer.parseInt( getVar( "SERVER_PORT" ) );
- }
- catch ( NumberFormatException e ) {
- return 80;
- }
- }
-
- /**
- * Returns the name of the user making this request, or null if not known.
- * Same as the CGI variable REMOTE_USER.
- */
- public String getRemoteUser() {
- return getVar( "REMOTE_USER" );
- }
-
- /**
- * Returns the IP address of the agent that sent the request.
- * Same as the CGI variable REMOTE_ADDR.
- */
- public String getRemoteAddr() {
- return getVar( "REMOTE_ADDR" );
- }
-
- /**
- * Returns the fully qualified host name of the agent that sent the
- * request.
- * Same as the CGI variable REMOTE_HOST.
- */
- public String getRemoteHost() {
- return getVar( "REMOTE_HOST" );
- }
-
- /**
- * Returns the authentication scheme of the request, or null if none.
- * Same as the CGI variable AUTH_TYPE.
- */
- public String getAuthType() {
- return getVar( "AUTH_TYPE" );
- }
-
- /**
- * Returns the value of a header field, or null if not known.
- * Same as the information passed in the CGI variabled HTTP_*.
- * @param name the header field name
- */
- public String getHeader( String name ) {
- if (name == null) return null;
- return getVar( "HTTP_" + name.replace('-','_').toUpperCase() );
- }
-
- /**
- * Returns the integer value of the specified header field.
- * @param name the header field name
- * @return the integer value of the header field, or -1 if the header
- * was not found
- */
- public int getIntHeader(String name) {
- String val = getHeader(name);
- if (val == null) return -1;
- try {
- return Integer.parseInt(val);
- } catch (NumberFormatException e) {
- return -1;
- }
- }
-
-
- /**
- * Returns the date value of the specified header field.
- * @param name the header field name
- * @return the date value of the header field in number of milliseconds
- * since the epoch, or -1 if the header was not found
- */
- public long getDateHeader(String name) {
- String val = getHeader(name);
- if (val == null) return -1;
- try {
- return Date.parse( val );
- } catch ( NumberFormatException e ) {
- return -1;
- }
- }
-
- /*
- * Possible request header field names.
- */
- private static String[] HEADERS = {
- /* Standard HTTP 1.0 and 1.1 headers */
- "Accept", "Accept-Charset", "Accept-Encoding",
- "Accept-Language", "Accept-Ranges", "Age",
- "Allow", "Authorization", "Cache-Control",
- "Connection", "Content-Base", "Content-Encoding",
- "Content-Language", "Content-Length", "Content-Location",
- "Content-MD5", "Content-Range", "Content-Type",
- "Date", "ETag", "Expires",
- "From", "Host", "If-Modified-Since",
- "If-Match", "If-None-Match", "If-Range",
- "If-Unmodified-Since", "Last-Modified", "Location",
- "Max-Forwards", "Pragma", "Proxy-Authenticate",
- "Proxy-Authorization", "Public", "Range",
- "Referer", "Retry-After", "Server",
- "Transfer-Encoding", "Upgrade", "User-Agent",
- "Vary", "Via", "Warning",
- "WWW-Authenticate",
- /* Popular extension headers */
- "Alternates", "Content-Version", "Cookie",
- "Derived-From", "Keep-Alive", "Link",
- "MIME-Version", "URI", "Title"
- };
-
-
- /**
- * Returns an Enumeration of the header names.
- */
- public Enumeration getHeaderNames() {
- Vector heads = new Vector();
- Enumeration enum = getVars();
- while (enum.hasMoreElements()) {
- String ohead = (String) enum.nextElement();
- if (ohead == null || ohead.length() < 5) continue;
- if (ohead.startsWith("HTTP_")) {
- String head = ohead.substring(5).toLowerCase().replace('_','-');
- for (int i = 0; i < HEADERS.length; i++) {
- if (head.equals(HEADERS[i].toLowerCase())) {
- heads.addElement(HEADERS[i]);
- break;
- }
- }
- }
- }
- return heads.elements();
- }
-
- /**
- * Returns an input stream for reading request data.
- */
- public ServletInputStream getInputStream(){
- return in;
- }
-
- /**
- * Returns an server specific attribute.
- */
- public Object getAttribute(String name) {
- return null;
- }
-
- private Hashtable nullHashtable = new Hashtable();
-
- private Hashtable getParametersFromRequest() {
-
- Hashtable h = null;
-
- if (getMethod().equals("GET")) {
- String s = getQueryString().toString();
- if (s != null) {
- try {
- h = HttpUtils.parseQueryString(s);
- } catch (IllegalArgumentException e) {
- h = null;
- }
- }
- } else if (getMethod().equals("POST")) {
- if (getContentType().equals("application/x-www-form-urlencoded")) {
- try {
- h = HttpUtils.parsePostData(getContentLength(),
- getInputStream());
- } catch (Exception e) {
- h = null;
- }
- }
- }
-
- if (h == null)
- h = nullHashtable;
-
- return h;
- }
-
- // Methods from HttpServletResponse.
-
- private int resCode = -1;
- private String resMessage = null;
- private Vector resHeaderNames = new Vector();
- private Vector resHeaderValues = new Vector();
-
- /** Sets the status code and message for this response.
- ** @param resCode the status code
- ** @param resMessage the status message
- */
- public void setStatus( int resCode, String resMessage )
- {
- this.resCode = resCode;
- this.resMessage = resMessage;
- }
-
- /** Sets the status code and a default message for this response.
- ** @param resCode the status code
- */
- public void setStatus( int resCode )
- {
- switch ( resCode )
- {
- case SC_OK: setStatus( resCode, "Ok" ); break;
- case SC_CREATED: setStatus( resCode, "Created" ); break;
- case SC_ACCEPTED: setStatus( resCode, "Accepted" ); break;
- case SC_NO_CONTENT: setStatus( resCode, "No content" ); break;
- case SC_MOVED_PERMANENTLY:
- setStatus( resCode, "Moved permanentently" ); break;
- case SC_MOVED_TEMPORARILY:
- setStatus( resCode, "Moved temporarily" ); break;
- case SC_NOT_MODIFIED: setStatus( resCode, "Not modified" ); break;
- case SC_BAD_REQUEST: setStatus( resCode, "Bad request" ); break;
- case SC_UNAUTHORIZED: setStatus( resCode, "Unauthorized" ); break;
- case SC_FORBIDDEN: setStatus( resCode, "Forbidden" ); break;
- case SC_NOT_FOUND: setStatus( resCode, "Not found" ); break;
- case SC_INTERNAL_SERVER_ERROR:
- setStatus( resCode, "Internal server error" ); break;
- case SC_NOT_IMPLEMENTED:
- setStatus( resCode, "Not implemented" ); break;
- case SC_SERVICE_UNAVAILABLE:
- setStatus( resCode, "Service unavailable" ); break;
- case SC_BAD_GATEWAY: setStatus( resCode, "Bad gateway" ); break;
- default: setStatus( resCode, "" ); break;
- }
- }
-
- /** Sets the content length for this response.
- ** @param length the content length
- */
- public void setContentLength( int length )
- {
- setIntHeader( "Content-length", length );
- }
-
- /** Sets the content type for this response.
- ** @param type the content type
- */
- public void setContentType( String type )
- {
- setHeader( "Content-type", type );
- }
-
- /** Sets the value of a header field.
- ** @param name the header field name
- ** @param value the header field value
- */
- public void setHeader( String name, String value )
- {
- resHeaderNames.addElement( name );
- resHeaderValues.addElement( value );
- }
-
- /**
- * Returns true iff the named header has been set.
- * @param name the header field name
- */
- public boolean containsHeader (String name)
- {
- return resHeaderNames.contains (name);
- }
-
- /** Sets the value of an integer header field.
- ** @param name the header field name
- ** @param value the header field integer value
- */
- public void setIntHeader( String name, int value )
- {
- setHeader( name, Integer.toString( value ) );
- }
-
- /** Sets the value of a date header field.
- ** @param name the header field name
- ** @param value the header field date value
- */
- public void setDateHeader( String name, long value )
- {
- setHeader( name, to1123String( new Date( value ) ) );
- }
-
- /// Converts a Date into an RFC-1123 string.
- private static String to1123String( Date date )
- {
- String ds = date.toString();
- int blank = ds.indexOf( ' ' );
- return
- ds.substring( 0, blank ) +
- ( date.getDate() < 10 ? ", 0" : ", " ) +
- date.toGMTString();
- }
-
- /** Returns an output stream for writing response data.
- */
- public ServletOutputStream getOutputStream()
- {
- return out;
- }
-
- private boolean headersWritten = false;
-
- /** Writes the status line and message headers for this response to the
- ** output stream.
- ** @exception IOException if an I/O error has occurred
- */
- void writeHeaders() throws IOException
- {
- if ( headersWritten )
- return;
- headersWritten = true;
- if ( getProtocol().startsWith( "HTTP/1" ) )
- {
- out.println( getProtocol() + " " + resCode + " " + resMessage );
- for ( int i = 0; i < resHeaderNames.size(); ++i )
- {
- String name = (String) resHeaderNames.elementAt( i );
- String value = (String) resHeaderValues.elementAt( i );
- if ( value != null ) // just in case
- out.println( name + ": " + value );
- }
- out.println( "" );
- out.flush();
- }
- }
-
- /** Writes an error response using the specified status code and message.
- ** @param resCode the status code
- ** @param resMessage the status message
- ** @exception IOException if an I/O error has occurred
- */
- public void sendError( int resCode, String resMessage ) throws IOException
- {
- setStatus( resCode, resMessage );
- realSendError();
- }
-
- /** Writes an error response using the specified status code and a default
- ** message.
- ** @param resCode the status code
- ** @exception IOException if an I/O error has occurred
- */
- public void sendError( int resCode ) throws IOException
- {
- setStatus( resCode );
- realSendError();
- }
-
- private void realSendError() throws IOException
- {
- setContentType( "text/html" );
- out.println( "<HTML><HEAD>" );
- out.println( "<TITLE>" + resCode + " " + resMessage + "</TITLE>" );
- out.println( "</HEAD><BODY BGCOLOR=\"#a0c0a0\">" );
- out.println( "<H2>" + resCode + " " + resMessage + "</H2>" );
- out.println( "<HR>" );
- serve.writeAddress( out );
- out.println( "</BODY></HTML>" );
- out.flush();
- }
-
- private void realSendError( Throwable t ) throws IOException
- {
- setContentType( "text/html" );
- writeHeaders();
- out.println( "<HTML><HEAD>" );
- out.println( "<TITLE>" + resCode + " " + resMessage + "</TITLE>" );
- out.println( "</HEAD><BODY BGCOLOR=\"#a0c0a0\">" );
- out.println( "<H2>" + resCode + " " + resMessage + "</H2>" );
- out.println( "<PRE><CODE>" );
- PrintStream p = new PrintStream( out );
- t.printStackTrace( p );
- p.flush();
- out.println( "</CODE></PRE>" );
- out.println( "<HR>" );
- serve.writeAddress( out );
- out.println( "</BODY></HTML>" );
- out.flush();
- }
-
- /** Sends a redirect message to the client using the specified redirect
- ** location URL.
- ** @param location the redirect location URL
- ** @exception IOException if an I/O error has occurred
- */
- public void sendRedirect( String location )
- throws IOException {
-
- setHeader( "Location", location );
- sendError( SC_MOVED_TEMPORARILY );
- }
-
- }
-
-
- class ServletGateConfig implements ServletConfig {
-
- private Properties servletProperties = new Properties();
- private ServletContext context;
- private String servletName;
-
- public ServletGateConfig(ServletContext context, String servletName,
- String propString) {
-
- this.context = context;
-
- if (propString != null) {
- propString = propString.replace(',','\n');
- StringBufferInputStream sbin =
- new StringBufferInputStream(propString);
- String line;
- DataInputStream ds = new DataInputStream(sbin);
- try {
- while ((line = ds.readLine()) != null) {
- int equalTo = line.indexOf("=");
- if (equalTo == -1)
- continue;
- String l = line.substring(0, equalTo);
- String r = line.substring(equalTo + 1, line.length());
- if (l != null && r != null)
- servletProperties.put(l,r);
- }
- } catch (IOException e) {
- System.err.println("Cannot read initial arguments for servlet "
- + servletName + ": ");
- e.printStackTrace(System.err);
- }
- }
- }
-
- // Methods from ServletConfig.
-
- /**
- * Returns the context for the servlet.
- */
- public ServletContext getServletContext() {
- return context;
- }
-
- /**
- * Gets an initialization parameter of the servlet.
- */
- public String getInitParameter( String name ) {
- // Default doesn't support servlet init params.
- return (String) servletProperties.get(name);
- }
-
- /**
- * Gets a enumeration of the initialization parameters of the servlet.
- */
- public Enumeration getInitParameterNames() {
- // Default doesn't support servlet init params.
- return servletProperties.propertyNames();
- }
- }
-
-
- /** Minimal implementation of ServletInputStream.
- */
-
- class AServletInputStream extends ServletInputStream
- {
-
- protected InputStream in;
-
- public AServletInputStream( InputStream in )
- {
- this.in = in;
- }
-
- public int readLine( byte[] b, int off, int len ) throws IOException
- {
- int off2 = off;
- for ( off2 = off; off2 - off < len; ++off2 )
- {
- int r = read();
- if ( r == -1 )
- {
- if ( off2 == off )
- return -1;
- break;
- }
- b[off2] = (byte) r;
- }
- return off2 - off;
- }
-
- public int read() throws IOException
- {
- return in.read();
- }
-
- public int read( byte[] b, int off, int len ) throws IOException
- {
- return in.read( b, off, len );
- }
-
- public int available() throws IOException
- {
- return in.available();
- }
-
- public void close() throws IOException
- {
- in.close();
- }
-
- }
-
-
- /** Minimal implementation of ServletOutputStream.
- */
-
- class AServletOutputStream extends ServletOutputStream
- {
-
- protected PrintStream out;
- protected ServletGateConnection conn;
-
- public AServletOutputStream( OutputStream out, ServletGateConnection conn )
- {
- this.out = new PrintStream( out );
- this.conn = conn;
- }
-
- public void write( int b ) throws IOException
- {
- conn.writeHeaders();
- out.write( b );
- }
-
- public void write( byte[] b, int off, int len ) throws IOException
- {
- conn.writeHeaders();
- out.write( b, off, len );
- }
-
- public void flush() throws IOException
- {
- conn.writeHeaders();
- out.flush();
- }
-
- public void close() throws IOException
- {
- conn.writeHeaders();
- out.close();
- }
-
- public void print( String s ) throws IOException
- {
- conn.writeHeaders();
- out.print( s );
- }
-
- public void print( int i ) throws IOException
- {
- conn.writeHeaders();
- out.print( i );
- }
-
- public void print( long l ) throws IOException
- {
- conn.writeHeaders();
- out.print( l );
- }
-
- public void println( String s ) throws IOException
- {
- conn.writeHeaders();
- out.print( s );
- println();
- }
-
- public void println( int i ) throws IOException
- {
- conn.writeHeaders();
- out.print( i );
- println();
- }
-
- public void println( long l ) throws IOException
- {
- conn.writeHeaders();
- out.print( l );
- println();
- }
-
- public void println() throws IOException
- {
- conn.writeHeaders();
- out.print("\r\n");
- out.flush();
- }
-
- }
-